package com.oktago.ibore;

import android.app.Application;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Credentials;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;

import org.apache.http.protocol.HttpContext;

public class IBoreApplication extends Application {

    String username, password, token;
    private DefaultHttpClient httpClient;
    boolean logged;
    boolean loginActivated=false;

    @Override
    public void onCreate() {
        super.onCreate();
        logged = false;
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        //releaseHttpClient();
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        releaseHttpClient();
    }

    /**
     * @return Il riferimento all'HttpClient ThreadSafe
     */
    public HttpClient getThreadSafeHttpClient() {
        if (httpClient == null) {
            initHttpClient();
        }
        return httpClient;
    }

    private final void initHttpClient() {
        // Per creare il corrispondente ThreadSafeClientConnManager abbiamo
        // bisogno delle informazioni relative al tipo di protocollo che intendiamo
        // gestire. Nel nostro caso definiamo il supporto per l'HTTP e l'HTTPS attraverso
        // la definizione di alcuni parametri e schemi
        HttpParams httpParams = new BasicHttpParams();
        // Impostiamo la versione del protocollo HTTP alla 1.1
        HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
        // Impostiamo il charset di default
        HttpProtocolParams.setContentCharset(httpParams, HTTP.DEFAULT_CONTENT_CHARSET);
        // Dobbiamo quindi descrivere quelli che sono i protocolli che intendiamo
        // gestire associando a ciascuno uno schema ed una Factory delle connessioni
        // Socket da utilizzare
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        // Gestiamo il protocollo HTTP nella porta 80
        Scheme httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
        schemeRegistry.register(httpScheme);
        // Gestiamo il protocollo HTTPS nella porta 443
        Scheme httpsScheme = new Scheme("https", SSLSocketFactory.getSocketFactory(), 443);
        schemeRegistry.register(httpsScheme);
        // Creiamo il ThreadSafeClientConnManager e lo assegnamo al client
        ClientConnectionManager tsConnManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
        httpClient = new DefaultHttpClient(tsConnManager, httpParams);
    }

    /*
     * Questo metodo permette di liberare le risorse occupate dal client ovvero
     * le diverse connessioni utilizzate. Per questo motivo andiamo a chiudere
     * le connessioni attraverso il ConnectionManager
     */
    private final void releaseHttpClient() {
        if (httpClient != null && httpClient.getConnectionManager() != null) {
            // Se esiste il ConnectionManager del client lo chiudiamo
            httpClient.getConnectionManager().shutdown();
        }
    }

    public void logout() {
        releaseHttpClient();
        logged = false;
        initHttpClient();
    }

    public static String cleanFileName(String s) {
        String res = s;
        res = res.replace(" ", "");
        res = res.replace("à", "a");
        res = res.replace("è", "e");
        res = res.replace("é", "e");
        res = res.replace("ì", "i");
        res = res.replace("ù", "u");
        res = res.replace("'", "");
        res = res.replace("/", "");
        return res.toLowerCase();
    }

    public Bitmap getImageFromTypeName(String typeName) {
        Bitmap res = Cache.getTypeIcon(typeName);
        if (res != null) {
            return res;
        }
        String iconFilename = cleanFileName(typeName) + ".png";
        res = BitmapFactory.decodeFile(Const.ICON_LOCAL_PATH + iconFilename);
        if (res == null && downloadIcon(typeName)) {
            res = BitmapFactory.decodeFile(Const.ICON_LOCAL_PATH + iconFilename);
            Cache.setTypeIcon(typeName, res);
        }        
        return res;
    }

    public void deleteIcons() {
        File dir = new File(Const.ICON_LOCAL_PATH);
        if (dir.exists()) {
            dir.delete();
        }
        dir.mkdirs();
    }

    public boolean downloadIcon(String typeName) {
        Log.d("download", "Inizio download icona per tipo " + typeName);
        String fileName = cleanFileName(typeName) + ".png";
        Log.d("download", "Nome icona: " + fileName);
        String path = Const.BASEPATH + Const.ICON_REMOTE_PATH + fileName;

        try {
            URL urlicon = new URL(path);

            Log.i("download", "Scarico il file " + fileName + " all'url " + path);
            URLConnection ucon = urlicon.openConnection();
            InputStream is = ucon.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is, 8192);
            FileOutputStream fos = new FileOutputStream(Const.ICON_LOCAL_PATH + fileName);
            int c = bis.read();
            while (c != -1) {
                fos.write(c);
                c = bis.read();
            }
            bis.close();
            fos.close();
            Log.i("D", "Finito");
            Bitmap res = BitmapFactory.decodeFile(Const.ICON_LOCAL_PATH + fileName);
            if (res != null) {
                Cache.setTypeIcon(typeName, res);
            }
            return true;
        } catch (Exception e) {
            return false;
        }

    }

    public void updateIcons() {
        deleteIcons();
        //TODO: scaricare con un apposito WS tutte le icone dell'applicazione
    }

    public Bitmap getLoginLogoutImage() {
        Bitmap res = null;
        if (logged) {
            res = Cache.getLogoutIcon();
        } else {
            res = Cache.getLoginIcon();
        }
        if (res != null) {
            return res;
        }
        if (logged) {
            String iconFilename = "logout.png";
            //la dovrei scaricare dal web
            //res = BitmapFactory.decodeFile(Const.ICON_LOCAL_PATH + iconFilename);
            res = BitmapFactory.decodeResource(getResources(), R.drawable.logout);
            Cache.setLogoutIcon(res);
        } else {
            String iconFilename = "login.png";
            //la dovrei scaricare dal web
            //res = BitmapFactory.decodeFile(Const.ICON_LOCAL_PATH + iconFilename);
            res = BitmapFactory.decodeResource(getResources(), R.drawable.login);
            Cache.setLoginIcon(res);
        }
        return res;
    }

    void startDownloadGet(ResponseHandler<String> myResponseHandler) throws URISyntaxException, IOException {
        HttpGet request = new HttpGet();
        URI target = new URI(Const.BASEPATH + Const.TOKEN_URL);
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

    void startDownloadPost(ResponseHandler<String> myResponseHandler, String username, String password, String token) throws UnsupportedEncodingException, URISyntaxException, IOException {

        HttpPost request = new HttpPost();

        ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("controller", "auth"));
        params.add(new BasicNameValuePair("option", "com_bore"));
        params.add(new BasicNameValuePair("remember", "yes"));
        params.add(new BasicNameValuePair("task", "login"));
        params.add(new BasicNameValuePair("username", username));
        params.add(new BasicNameValuePair("passwd", password));
        params.add(new BasicNameValuePair("" + token, "1"));

        request.setEntity(new UrlEncodedFormEntity(params));

        URI target = new URI(Const.BASEPATH + Const.LOGIN_URL);
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

    void setLogged(String username, String password, String token) {
        this.username = username;
        this.password = password;
        this.token = token;
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(Const.BASEPATH, AuthScope.ANY_PORT), new UsernamePasswordCredentials(username, password));
        httpClient.setCredentialsProvider(credsProvider);

        HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {

            public void process(
                    final HttpRequest request,
                    final HttpContext context) throws HttpException, IOException {

                AuthState authState = (AuthState) context.getAttribute(
                        ClientContext.TARGET_AUTH_STATE);
                CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
                        ClientContext.CREDS_PROVIDER);
                HttpHost targetHost = (HttpHost) context.getAttribute(
                        ExecutionContext.HTTP_TARGET_HOST);

                // If not auth scheme has been initialized yet
                if (authState.getAuthScheme() == null) {
                    AuthScope authScope = new AuthScope(
                            targetHost.getHostName(),
                            targetHost.getPort());
                    // Obtain credentials matching the target host
                    Credentials creds = (Credentials) credsProvider.getCredentials(authScope);
                    // If found, generate BasicScheme preemptively
                    if (creds != null) {
                        authState.setAuthScheme(new BasicScheme());
                        authState.setCredentials((org.apache.http.auth.Credentials) creds);
                    }
                }
            }
        };

        httpClient.addRequestInterceptor(preemptiveAuth);
        logged = true;
    }

    public void countInstances(long idt, Long root, ResponseHandler<String> myResponseHandler) throws URISyntaxException, IOException {
        HttpGet request = new HttpGet();
        URI target = null;
        if (root==null) {
             target = new URI(Const.BASEPATH + Const.COUNT_ROOT_SUBTYPES_URL.replace("<idt>", idt + ""));
        }
        else {
            target = new URI(Const.BASEPATH + Const.COUNT_NODE_SUBTYPES_URL.replace("<idt>", idt + "").replace("<root>",root.toString()));
        }
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

    public void downloadList(long idt, Long root, int page, int itemsPerPage, ResponseHandler<String> myResponseHandler) throws URISyntaxException, IOException {
        HttpGet request = new HttpGet();
        URI target = null;
        if (root==null) {
            target=new URI(Const.BASEPATH + Const.LIST_ROOT_SUBTYPES_URL.replace("<idt>", "" + idt).replace("<page>", "" + page).replace("<ipp>", "" + itemsPerPage));
        }
        else {
            target=new URI(Const.BASEPATH + Const.LIST_NODE_SUBTYPES_URL.replace("<idt>", "" + idt).replace("<page>", "" + page).replace("<ipp>", "" + itemsPerPage).replace("<root>",root.toString()));
        }
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

    public void downloadNode(Long id, ResponseHandler<String> myResponseHandler) throws URISyntaxException, IOException {
        HttpGet request = new HttpGet();
        URI target = null;
        if (id==null) {
            target=new URI(Const.BASEPATH + Const.ROOT_TYPES_PATH);
        }
        else {
            target=new URI(Const.BASEPATH + Const.SUB_TYPES_PATH.replace("<id>", "" + id));
        }
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

    public void downloadDetail(long id, ResponseHandler<String> myResponseHandler) throws URISyntaxException, IOException {
        HttpGet request = new HttpGet();
        URI target = new URI(Const.BASEPATH + Const.INSTANCE_DETAIL_URL.replace("<id>", "" + id));
        request.setURI(target);
        getThreadSafeHttpClient().execute(request, myResponseHandler);
    }

}
